package per.sunmes.lesrb.actor;

import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.maps.MapLayer;
import com.badlogic.gdx.maps.tiled.TiledMap;
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer;
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer.Cell;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.utils.Array;

import per.sunmes.lesrb.util.U;

public class TiledMapActor extends Actor {

	TiledMap tiledMap;
	Array<TiledMapTileLayer> drawLayers = new Array<TiledMapTileLayer>();
	Rectangle drawBound = new Rectangle();
	int startX, endX, startY, endY;
	float offX, offY;
	float tileWidth, tileHeight;
	int tileMaxX, tileMaxY;

	float tileMapWidth, tileMapHeight;

	public TiledMapActor(TiledMap map) {
		U.stageSize(this);
		this.tiledMap = map;
		for (int i = 0; i < map.getLayers().getCount(); i++) {
			MapLayer layer = map.getLayers().get(i);
			if (layer instanceof TiledMapTileLayer) {
				TiledMapTileLayer tl = (TiledMapTileLayer) layer;
				drawLayers.add(tl);
				if (tileWidth == 0) {
					tileWidth = tl.getTileWidth();
					tileHeight = tl.getTileHeight();
					tileMaxX = tl.getWidth();
					tileMaxY = tl.getHeight();

					tileMapWidth = tileWidth * tileMaxX;
					tileMapHeight = tileHeight * tileMaxY;
				}
			}
		}

		if (tileWidth == 0 || tileHeight == 0) {
			System.out.println("TiledMap has no tiledMapTileLayer...");
		}

		drawBound.set(0, 0, getWidth(), getHeight());

		recalcDrawZone();
	}

	public void setDrawPos(float x, float y) {
		drawBound.set(x, y, drawBound.getWidth(), drawBound.getHeight());
		recalcDrawZone();
	}

	public float getTileWidth() {
		return tileWidth;
	}

	public float getTileHeight() {
		return tileHeight;
	}

	public float getTileMapHeight() {
		return tileMapHeight;
	}

	public float getTileMapWidth() {
		return tileMapWidth;
	}

	public int getTileMaxX() {
		return tileMaxX;
	}

	public int getTileMaxY() {
		return tileMaxY;
	}

	float lastX, lastY;

	@Override
	public void act(float delta) {
		super.act(delta);

		if (Math.abs(drawBound.getX() - lastX) >= tileWidth || Math.abs(drawBound.getY() - lastY) >= tileHeight) {
			lastX = drawBound.getX();
			lastY = drawBound.getY();
			recalcDrawZone();
		} else {
			offX = startX * tileWidth - drawBound.getX();
			offY = startY * tileHeight - drawBound.getY();
		}
	}

	public void recalcDrawZone() {
		if (tileWidth != 0 && tileHeight != 0) {
			startX = Math.max(0, Math.round(drawBound.x / tileWidth) - 1);
			offX = startX * tileWidth - drawBound.x;
			endX = Math.min(tileMaxX, (int) Math.ceil((drawBound.x + drawBound.width) / tileWidth) + 1);

			startY = Math.max(0, Math.round(drawBound.y / tileHeight) - 1);
			offY = startY * tileHeight - drawBound.y;
			endY = Math.min(tileMaxY, (int) Math.ceil((drawBound.y + drawBound.height) / tileHeight) + 1);
		}
	}

	public TiledMap getTiledMap() {
		return tiledMap;
	}

	public Rectangle getDrawBound() {
		return drawBound;
	}

	@Override
	public void draw(Batch batch, float parentAlpha) {
		batch.setColor(Color.WHITE);
		for (int i = 0; i < drawLayers.size; i++) {
			TiledMapTileLayer layer = drawLayers.get(i);
			if (!layer.isVisible()) {
				continue;
			}
			for (int y = startY; y <= endY; y++) {
				for (int x = startX; x <= endX; x++) {
					Cell cell = layer.getCell(x, y);
					if (cell != null) {
						batch.draw(cell.getTile().getTextureRegion(), getX() + offX + (x - startX) * tileWidth,
								getY() + offY + (y - startY) * tileHeight);
					}
				}
			}
		}
	}

}
